# -*- coding: utf-8 -*-
import requests
from lxml import etree
import re
import time
from loguru import logger
import random
import datetime
import execjs
import traceback
import threading
import sys
import os
import json
from queue import Queue, Empty
from fake_useragent import UserAgent
import concurrent.futures
from src.config.conf import cfg
from src.service.requests_middler import requests_sys
from src.service.requests_middler import proxy_requests_sys
from src.service.requests_middler import insert_shipping_info
from src.service.requests_middler import read_excel
from src.service.requests_middler import read_transport_json
from src.service.requests_middler import get_proxies

current_working_directory = os.getcwd()
ip_queue = Queue()
ua = UserAgent()
random_user_agent = ua.random
stop_threading_event = threading.Event()

total_requests = 0
loss_requests = 0

def proxies_queue():
    # 获取代理并放入队列
    if ip_queue.empty():
        proxy = get_proxies()
        logger.info(f"获取ip代理成功: {proxy}")
        if proxy:
            ip_queue.put(proxy)
        else:
            logger.error(f"获取ip代理失败")
    else:
        proxy = ip_queue.get()
        return proxy


def get_date(time_str):
    # 解析时间字符串为 datetime 对象
    original_time = datetime.datetime.strptime(time_str, "%Y-%m-%dT%H:%M%z")

    # 将本地时间转换为 UTC 时间
    utc_time = original_time.astimezone(datetime.timezone.utc)

    # 检查转换后的时间是否超过了 16:00
    if utc_time.hour >= 16:
        # 如果超过16:00，则日期应该是第二天
        utc_time += datetime.timedelta(days=1)

    # 格式化输出日期，格式为 "Y-M-D"
    formatted_date = utc_time.strftime("%Y-%m-%d")
    return formatted_date


def hapag_transport(origin_city, destination_city):
    global total_requests
    global loss_requests
    port_mapping = {}
    # file_path = "../maeu_ports.json"
    # file_path = "maeu_ports.json"
    # file_path = os.path.join(current_working_directory + r'/src/crawler', file_path)
    # file_path = os.path.join(os.path.dirname(os.getcwd()), file_path)  #windows
    file_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'maeu_ports.json')
    if os.path.exists(file_path):
        with open(file_path, "r") as file:
            Menu_json = json.load(file)
    else:
        logger.error(f"不存在文件: {file_path}")
        sys.exit()
    for info in Menu_json['ports']:
        port_mapping[info['portName'].upper()] = {
            'portCode': info.get('portCode'),
            'unLocationCode': info['unLocationCode']
        }
    origin_info = port_mapping.get(origin_city.upper())
    destination_info = port_mapping.get(destination_city.upper())
    if origin_info and destination_info:
        total_requests += 1
        date = datetime.datetime.now().strftime('%Y-%m-%d')
        origin_unLocationCode = origin_info['unLocationCode']
        if origin_city.upper() == "TIANJIN":
            origin_unLocationCode = "CNTXG"
        elif origin_city.upper() == "NINGBO":
            origin_unLocationCode = "CNNGB"
        print(origin_unLocationCode)
        des_unLocationCode = destination_info['unLocationCode']
        headers = {
            "accept": "application/json, text/plain, */*",
            "accept-language": "zh-CN,zh;q=0.9",
            "cache-control": "no-cache",
            "origin": "https://www.hapag-lloyd.cn",
            "pragma": "no-cache",
            "priority": "u=1, i",
            "referer": "https://www.hapag-lloyd.cn/",
            "sec-ch-ua": "\"Google Chrome\";v=\"129\", \"Not=A?Brand\";v=\"8\", \"Chromium\";v=\"129\"",
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": "\"Windows\"",
            "sec-fetch-dest": "empty",
            "sec-fetch-mode": "cors",
            "sec-fetch-site": "cross-site",
            "user-agent": random_user_agent,
            "x-token": "public"
        }
        url = "https://schedule.api.hlag.cloud/api/routes"
        params = {
            "startLocation": origin_unLocationCode,
            "endLocation": des_unLocationCode,
            "startDate": f"{date}",
            "startHaulage": "MERCHANT",
            "endHaulage": "MERCHANT",
            "containerType": "45RT",
            "isNonOperatingReefer": "true"
        }
        retry_count = 0
        while retry_count < 3:
            proxies = proxies_queue()
            # res = requests_sys(url, headers=headers, params=params, GET=True)
            res = proxy_requests_sys(url, headers=headers, params=params, GET=True, proxies=proxies)
            if res:
                ip_queue.put(proxies)
                js_data = res.json()
                if js_data.get("routes"):
                    logger.info(f"当前查询 起点:{origin_city} ----> 终点: {destination_city}")
                    logger.info(f"当前请求总数: {total_requests}, 失败请求总数: {loss_requests}")
                    for info in js_data['routes']:
                        item = {}
                        # 处理中转
                        item['origin_code'] = f"{origin_city}({origin_info['unLocationCode']})"
                        if len(info['legs']) >= 2:
                            logger.info(f"{item['origin_code']}: {origin_city} ----> {destination_city} 存在中转站")
                            des_city = destination_city.upper()
                            if port_mapping.get(des_city.upper()):
                                unLocationCode = des_unLocationCode
                                country_code = check_country_code(unLocationCode)
                                item['destination_code'] = f"{des_city},{country_code}({unLocationCode})"  # check
                                item['depart_date'] = datetime.datetime.fromisoformat(
                                    info['placeOfReceiptDateTime']).strftime("%Y-%m-%d")
                                item['arrive_date'] = get_date(info['placeOfDeliveryDateTime'])
                                item['transport_contractor'] = "Hapag-Lloyd"
                                item['haulage_time'] = info['transitTimeInDays']
                                item['ship_name'] = info['legs'][-1].get('vesselDetails', {}).get('name')
                                item['voyage_number'] = info['legs'][-1].get('scheduleVoyageNumber')
                                if list(info['legs'])[-1]['modeOfTransport'] == 'VESSEL':
                                    item['ship_name'] = info['legs'][-1].get('vesselDetails', {}).get('name')
                                    item['voyage_number'] = info['legs'][-1].get('scheduleVoyageNumber')
                                    if not item['voyage_number']:
                                        item['ship_name'] = info['legs'][-2].get('vesselDetails', {}).get('name')
                                        item['voyage_number'] = info['legs'][-2].get('scheduleVoyageNumber')
                                else:
                                    for transfer in list(reversed(info['legs']))[1:]:
                                        if transfer['modeOfTransport'] == 'VESSEL':
                                            item['ship_name'] = transfer['vesselDetails']['name']
                                            item['voyage_number'] = transfer['scheduleVoyageNumber']
                                            break
                                code = ''
                                city = ''
                                item['transfer_code'] = None
                                for transfer in list(reversed(info['legs']))[1:]:
                                    if transfer['modeOfTransport'] == 'VESSEL':

                                        city = transfer['arrivalLocation']['locationName'].split(',')[0]
                                        code = transfer['arrivalLocation']['unLocationCode']
                                        break
                                if code != '' and city!= '' and check_code(code):
                                    item['transfer_code'] = f'{city}({code})'
                                item['shipping_lanes'] = info["legs"][0]["serviceCode"]
                                # print(item)
                                insert_shipping_info(item)
                            else:

                                logger.info(f"起点:{origin_city} ----> 终点: {destination_city} 未查询到数据")
                        else:
                            des_city = destination_city.upper()
                            if port_mapping.get(des_city.upper()):
                                unLocationCode = des_unLocationCode
                                country_code = check_country_code(unLocationCode)
                                item['destination_code'] = f"{des_city},{country_code}({unLocationCode})"  # check
                                item['depart_date'] = datetime.datetime.fromisoformat(
                                    info['placeOfReceiptDateTime']).strftime("%Y-%m-%d")
                                item['arrive_date'] = get_date(info['placeOfDeliveryDateTime'])
                                item['transport_contractor'] = "Hapag-Lloyd"
                                item['haulage_time'] = info['transitTimeInDays']
                                item['ship_name'] = info['legs'][-1].get('vesselDetails', {}).get('name')
                                item['voyage_number'] = info['legs'][-1].get('scheduleVoyageNumber')
                                item['transfer_code'] = None
                                item['shipping_lanes'] = info["legs"][0]["serviceCode"]
                                # print(item)
                                insert_shipping_info(item)

                            else:
                                logger.info(f"起点:{origin_city} ----> 终点: {destination_city} 未查询到数据")
                else:
                    logger.info(f"起点:{origin_city} ----> 终点: {destination_city} 未查询到数据")
                    read_transport_json(transport='Hapag-Lloyd', origin_city=origin_city, des_city=destination_city,
                                   fail_result="未查询到数据")
                    loss_requests += 1
                    retry_count += 1
                break
            elif res is None:
                loss_requests += 1
                retry_count += 1
                logger.info(f"起点:{origin_city} ----> 终点: {destination_city} 未查询到数据")
                read_transport_json(transport='Hapag-Lloyd', origin_city=origin_city, des_city=destination_city,
                               fail_result="未查询到数据")
            elif res == 0:
                logger.info(f"起点:{origin_city} ----> 终点: {destination_city} 请求超时")
                # read_transport_json(transport='Hapag-Lloyd', origin_city=origin_city, des_city=destination_city,
                #                fail_result="请求超时")
                retry_count += 1
        if retry_count == 3:
            read_transport_json(transport='Hapag-Lloyd', origin_city=origin_city, des_city=destination_city,
                                fail_result="请求超时")
#Hapag-Lloyd

def process_route(origin_city, destination_list):
    for destination_city in destination_list:
        hapag_transport(origin_city, destination_city)

def hapag_spider_run():
    global total_requests
    global loss_requests
    # origin_city_list = [
    #     "Shanghai", "XIAMEN", "NANSHA", "QINGDAO", "YANTIAN", "NINGBO", "Tianjin"
    # ]
    # destination_list = [
    #     "Los Angeles", "Long Beach", "Atlanta", "Baltimore", "Boston", "Buffalo", "Calgary", "Charleston",
    #     "Chicago", "Chippewa Falls", "Cincinnati", "Cleveland", "Dallas", "Denver",
    #     "Detroit", "Edmonton", "EI Paso", "Halifax", "Houston", "Jacksonville",
    #     "Kansas City", "Louisville", "Memphis", "Miami", "Minneapolis", "Montreal",
    #     "Nashville", "New Orleans", "New York", "Norfolk", "Oakland", "Omaha",
    #     "Philadelphia", "Pittsburgh", "Portland", "Prince Rupert", "Saint Louis",
    #     "Salt Lake City", "San Antonio", "Saskatoon", "Savannah", "Seattle",
    #     "Tacoma", "Tampa", "Toronto", "Vancouver", "Winnipeg"
    # ]

    json_path_one = r"origin_and_destination.json"
    json_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), json_path_one)
    with open(f'{json_path}', 'r', encoding='utf-8') as f:
        tmp = json.loads(f.read())

    origin_city_list = tmp['origin_city_list']
    destination_list = tmp['destination_list']
    del tmp, json_path, json_path_one
    # with concurrent.futures.ThreadPoolExecutor() as executor:
    #     futures = [executor.submit(process_route, origin_city, destination_list) for origin_city in origin_city_list]
    with concurrent.futures.ThreadPoolExecutor() as executor:
        futures = []
        for origin_city in origin_city_list:
            future = executor.submit(process_route, origin_city, destination_list)
            futures.append(future)
            time.sleep(1)

        for future in concurrent.futures.as_completed(futures):
            try:
                future.result()
            except Exception as e:
                # 输出异常详细信息，包括出错的行号
                print(f"An error occurred: {e}")
                print(traceback.format_exc())
    read_excel(transport="Hapag-Lloyd", total_requests=total_requests, loss_requests=loss_requests)


def check_code(code):
    file_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'maeu_ports.json')
    # with open(os.getcwd() + r'/src/crawler/' + 'maeu_ports.json', 'r') as f:
    with open(file_path, 'r') as f:
        result = f.read()
        f.close()
    null = ''
    true = ''
    false = ''
    result = eval(result)['ports']
    for res in result:
        if code == res['unLocationCode'] and code[0:2] == 'US':
            return True
    return False


def check_country_code(code):
    file_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'maeu_ports.json')
    # with open(os.getcwd() + r'/src/crawler/' + 'maeu_ports.json', 'r') as f:
    with open(file_path, 'r') as f:
        result = f.read()
        f.close()
    null = ''
    true = ''
    false = ''
    result = eval(result)['ports']
    for res in result:
        if code == res['unLocationCode'] and code[0:2] == 'US':
            try:
                code = res['regionCode']
                return code
            except:
                return ''
    return ''


if __name__ == '__main__':
    hapag_spider_run()

